/**
 *  CodeCompiler.java : IceBird project
 *  19:10:21 
 */
package icebird.compiler.ncomp;

import java.util.HashMap;
import java.util.Map;

import icebird.compiler.bytecode.BytecodeVisitor;
import icebird.compiler.ncomp.X86Register.GPR;
import icebird.compiler.ncomp.vs.DoubleConstantLocation;
import icebird.compiler.ncomp.vs.DoubleItem;
import icebird.compiler.ncomp.vs.DoubleWordItem;
import icebird.compiler.ncomp.vs.FPUStack;
import icebird.compiler.ncomp.vs.FloatConstantLocation;
import icebird.compiler.ncomp.vs.FloatItem;
import icebird.compiler.ncomp.vs.GPRLocation;
import icebird.compiler.ncomp.vs.IntegerConstantLocation;
import icebird.compiler.ncomp.vs.IntegerItem;
import icebird.compiler.ncomp.vs.Item;
import icebird.compiler.ncomp.vs.LocalLocation;
import icebird.compiler.ncomp.vs.Location;
import icebird.compiler.ncomp.vs.LongConstantLocation;
import icebird.compiler.ncomp.vs.LongItem;
import icebird.compiler.ncomp.vs.VirtualStack;
import icebird.compiler.ncomp.vs.WordItem;
import icebird.metadata.BasicType;
import icebird.metadata.Method;
import icebird.metadata.SpecialMethod;
import icebird.metadata.StaticMethod;
import icebird.metadata.constpool.ConstClass;
import icebird.metadata.constpool.ConstField;
import icebird.metadata.constpool.ConstIMethod;
import icebird.metadata.constpool.ConstMethod;

/**
 * @author Sergey Shulepoff[Knott]
 */
public final class CodeCompiler extends BytecodeVisitor {
	
	private X86RegisterPool pool;
	private X86Assembler asm;
	
	private VirtualStack stack;
	
	private static CodeCompiler code;
	
	private Map<Integer, Item> constLocals = new HashMap<Integer, Item>();
	
	private StackFrame stackFrame;
	
	private FPCompiler fp;
	
	public CodeCompiler() {
		pool = new X86RegisterPool();
		asm = new X86TextAssembler();
		
		stack = new VirtualStack();
		
		code = this;
		
		stackFrame = new StackFrame();
		
		fp = null;
		if (fp ==null) fp = null;
	}
	
	/**
	 * Request one register.
	 * @return X86Register
	 */
	public GPR request(BasicType type) {
		X86Register reg = pool.request(type);
		if (reg == null) {
			stack.push();
			reg = pool.request(type);
		}
		
		return (GPR)reg;
	}
	
	/**
	 * Gets code.
	 * @return CodeCompiler
	 */
	public static CodeCompiler getCompiler() {
		return code;
	}
	
	/**
	 * Gets x86 assembler.
	 * @return X86Assembler
	 */
	public X86Assembler getAssembler() {
		return asm;
	}
	
	/**
	 * Gets register pool.
	 * @return X86RegisterPool
	 */
	public X86RegisterPool getPool() {
		return pool;
	}
	
	/**
	 * Returns virtual stack.
	 * @return VirtualStack
	 */
	public VirtualStack getVS() {
		return stack;
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#endInstruction()
	 */
	@Override
	public void endInstruction() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#endMethod()
	 */
	@Override
	public void endMethod() {
		stackFrame.emitTrailer();
		
		asm.setMethodArea(false);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#startInstruction(int, byte)
	 */
	@Override
	public void startInstruction(int pc, byte opcode) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#startMethod(icebird.metadata.Method)
	 */
	@Override
	public boolean startMethod(Method method) {
		Label l = new Label(method.getMangledName());
		asm.bind(l);
		
		asm.setMethodArea(true);
		
		stackFrame.emitHeader();
		
		return true;
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_aaload()
	 */
	@Override
	public void visit_aaload() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_aastore()
	 */
	@Override
	public void visit_aastore() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_aconst_null()
	 */
	@Override
	public void visit_aconst_null() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_aload(int)
	 */
	@Override
	public void visit_aload(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_anewarray(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_anewarray(ConstClass clazz) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_areturn()
	 */
	@Override
	public void visit_areturn() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_arraylength()
	 */
	@Override
	public void visit_arraylength() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_astore(int)
	 */
	@Override
	public void visit_astore(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_athrow()
	 */
	@Override
	public void visit_athrow() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_baload()
	 */
	@Override
	public void visit_baload() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_bastore()
	 */
	@Override
	public void visit_bastore() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_caload()
	 */
	@Override
	public void visit_caload() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_castore()
	 */
	@Override
	public void visit_castore() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_checkcast(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_checkcast(ConstClass clazz) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_d2f()
	 */
	@Override
	public void visit_d2f() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_d2i()
	 */
	@Override
	public void visit_d2i() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_d2l()
	 */
	@Override
	public void visit_d2l() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dadd()
	 */
	@Override
	public void visit_dadd() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_daload()
	 */
	@Override
	public void visit_daload() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dastore()
	 */
	@Override
	public void visit_dastore() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dcmpg()
	 */
	@Override
	public void visit_dcmpg() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dcmpl()
	 */
	@Override
	public void visit_dcmpl() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dconst(double)
	 */
	@Override
	public void visit_dconst(double value) {
		stack.push(new DoubleItem(new DoubleConstantLocation(value)));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ddiv()
	 */
	@Override
	public void visit_ddiv() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dload(int)
	 */
	@Override
	public void visit_dload(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dmul()
	 */
	@Override
	public void visit_dmul() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dneg()
	 */
	@Override
	public void visit_dneg() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_drem()
	 */
	@Override
	public void visit_drem() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dreturn()
	 */
	@Override
	public void visit_dreturn() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dstore(int)
	 */
	@Override
	public void visit_dstore(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dsub()
	 */
	@Override
	public void visit_dsub() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup()
	 */
	@Override
	public void visit_dup() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup2()
	 */
	@Override
	public void visit_dup2() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup2_x1()
	 */
	@Override
	public void visit_dup2_x1() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup2_x2()
	 */
	@Override
	public void visit_dup2_x2() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup_x1()
	 */
	@Override
	public void visit_dup_x1() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup_x2()
	 */
	@Override
	public void visit_dup_x2() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_f2d()
	 */
	@Override
	public void visit_f2d() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_f2i()
	 */
	@Override
	public void visit_f2i() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_f2l()
	 */
	@Override
	public void visit_f2l() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fadd()
	 */
	@Override
	public void visit_fadd() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_faload()
	 */
	@Override
	public void visit_faload() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fastore()
	 */
	@Override
	public void visit_fastore() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fcmpg()
	 */
	@Override
	public void visit_fcmpg() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fcmpl()
	 */
	@Override
	public void visit_fcmpl() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fconst(float)
	 */
	@Override
	public void visit_fconst(float value) {
		stack.push(new FloatItem(new FloatConstantLocation(value)));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fdiv()
	 */
	@Override
	public void visit_fdiv() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fload(int)
	 */
	@Override
	public void visit_fload(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fmul()
	 */
	@Override
	public void visit_fmul() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fneg()
	 */
	@Override
	public void visit_fneg() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_frem()
	 */
	@Override
	public void visit_frem() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_freturn()
	 */
	@Override
	public void visit_freturn() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fstore(int)
	 */
	@Override
	public void visit_fstore(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fsub()
	 */
	@Override
	public void visit_fsub() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_getfield(icebird.metadata.constpool.ConstField)
	 */
	@Override
	public void visit_getfield(ConstField fieldRef) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_getstatic(icebird.metadata.constpool.ConstField)
	 */
	@Override
	public void visit_getstatic(ConstField fieldRef) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_goto(int)
	 */
	@Override
	public void visit_goto(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2b()
	 */
	@Override
	public void visit_i2b() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2c()
	 */
	@Override
	public void visit_i2c() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2d()
	 */
	@Override
	public void visit_i2d() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2f()
	 */
	@Override
	public void visit_i2f() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2l()
	 */
	@Override
	public void visit_i2l() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2s()
	 */
	@Override
	public void visit_i2s() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iadd()
	 */
	@Override
	public void visit_iadd() {
		iop(X86Operation.ADD, true);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iaload()
	 */
	@Override
	public void visit_iaload() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iand()
	 */
	@Override
	public void visit_iand() {
		iop(X86Operation.AND, true);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iastore()
	 */
	@Override
	public void visit_iastore() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iconst(int)
	 */
	@Override
	public void visit_iconst(int value) {
		stack.push(new IntegerItem(new IntegerConstantLocation(value)));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_idiv()
	 */
	@Override
	public void visit_idiv() {
		IntegerItem v2 = stack.popInteger();
		IntegerItem v1 = stack.popInteger();
		
		if (isConstant(v2)) {
			
			// Both constant - make compile time
			// operation.
			if (isConstant(v1)) {
				visit_iconst(
					((IntegerConstantLocation)v1.getLocation()).getValue() /
					((IntegerConstantLocation)v2.getLocation()).getValue()
				);
			} else {
				int value = ((IntegerConstantLocation)v2.getLocation()).getValue(); 
				int shift = getShiftForMultiplier(value);
				
				if (shift > 0) {
					v1.load();
					asm.sar(((GPRLocation)v1.getLocation()).getGPR(), shift);
					
					stack.push(v1);
				} else {
					v2.load();					
					v1.loadTo(X86Register.EAX);
					
					asm.idiv(((GPRLocation)v2.getLocation()).getGPR());
					
					stack.push(v1);
				}
			}
			
			v2.release();
		} else {
			v2.load();					
			v1.loadTo(X86Register.EAX);
			
			asm.idiv(((GPRLocation)v2.getLocation()).getGPR());
			
			stack.push(v1);
			v2.release();
		}
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_acmpeq(int)
	 */
	@Override
	public void visit_if_acmpeq(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_acmpne(int)
	 */
	@Override
	public void visit_if_acmpne(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmpeq(int)
	 */
	@Override
	public void visit_if_icmpeq(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmpge(int)
	 */
	@Override
	public void visit_if_icmpge(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmpgt(int)
	 */
	@Override
	public void visit_if_icmpgt(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmple(int)
	 */
	@Override
	public void visit_if_icmple(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmplt(int)
	 */
	@Override
	public void visit_if_icmplt(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmpne(int)
	 */
	@Override
	public void visit_if_icmpne(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifeq(int)
	 */
	@Override
	public void visit_ifeq(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifge(int)
	 */
	@Override
	public void visit_ifge(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifgt(int)
	 */
	@Override
	public void visit_ifgt(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifle(int)
	 */
	@Override
	public void visit_ifle(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iflt(int)
	 */
	@Override
	public void visit_iflt(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifne(int)
	 */
	@Override
	public void visit_ifne(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifnonnull(int)
	 */
	@Override
	public void visit_ifnonnull(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifnull(int)
	 */
	@Override
	public void visit_ifnull(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iinc(int, int)
	 */
	@Override
	public void visit_iinc(int index, int incValue) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iload(int)
	 */
	@Override
	public void visit_iload(int index) {
		wload(BasicType.Int, index);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_imul()
	 */
	@Override
	public void visit_imul() {
		IntegerItem v2 = stack.popInteger();
		IntegerItem v1 = stack.popInteger();
		
		if (isConstant(v1, v2)) {
			visit_iconst(
					((IntegerConstantLocation)v1.getLocation()).getValue() *
					((IntegerConstantLocation)v2.getLocation()).getValue()
				);
		} else {
			if (prepare(v1, v2, true)) {
				// (Un)Swap
				IntegerItem tmp = v2;
                v2 = v1;
                v1 = tmp;
			}
			
			Location l = v2.getLocation();
			GPR r1 = ((GPRLocation)v1.getLocation()).getGPR();
			
			if (l.isGPR()) {
				asm.imul(r1, ((GPRLocation)l).getGPR());
			}
			
			if (l.isConstant()) {
				int value = ((IntegerConstantLocation)l).getValue();
				
				if (value == 0) {
					asm.clear(r1); // x * 0 = 0
				} else if (value == -1) {
					asm.neg(r1); // x * -1 = -x
				} else {
					int shift = getShiftForMultiplier(Math.abs(value));
					
					if (shift > 0) {
						asm.sal(r1, shift);
						if (value < 0) {
							asm.neg(r1);
						}
					} else {
						asm.imul(r1, r1, value);
					}
				}
			}
			
			v2.release();
		}
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ineg()
	 */
	@Override
	public void visit_ineg() {
		IntegerItem i = stack.popInteger();
		
		if (i.getLocation().isConstant()) {
			visit_iconst(-((IntegerConstantLocation)i.getLocation()).getValue());
		} else {
			i.load();
			asm.neg(((GPRLocation)i.getLocation()).getGPR());
			
			stack.push(i);
		}
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_instanceof(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_instanceof(ConstClass clazz) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_invokeinterface(icebird.metadata.constpool.ConstIMethod, int)
	 */
	@Override
	public void visit_invokeinterface(ConstIMethod methodRef, int count) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_invokespecial(icebird.metadata.constpool.ConstMethod)
	 */
	@Override
	public void visit_invokespecial(ConstMethod methodRef) {
		SpecialMethod m = (SpecialMethod)methodRef.getConstClass().getClassDef().getMethod(methodRef);
		
		stack.push();
		dropParameters(m, true);
		
		callMethod(m);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_invokestatic(icebird.metadata.constpool.ConstMethod)
	 */
	@Override
	public void visit_invokestatic(ConstMethod methodRef) {
		StaticMethod m = (StaticMethod)methodRef.getConstClass().getClassDef().getMethod(methodRef);
		
		stack.push();
		dropParameters(m, false);
		
		callMethod(m);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_invokevirtual(icebird.metadata.constpool.ConstMethod)
	 */
	@Override
	public void visit_invokevirtual(ConstMethod methodRef) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ior()
	 */
	@Override
	public void visit_ior() {
		iop(X86Operation.OR, true);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_irem()
	 */
	@Override
	public void visit_irem() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ireturn()
	 */
	@Override
	public void visit_ireturn() {
		wreturn(BasicType.Int, true);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ishl()
	 */
	@Override
	public void visit_ishl() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ishr()
	 */
	@Override
	public void visit_ishr() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_istore(int)
	 */
	@Override
	public void visit_istore(int index) {
		wstore(BasicType.Int, index);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_isub()
	 */
	@Override
	public void visit_isub() {
		iop(X86Operation.SUB, true);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iushr()
	 */
	@Override
	public void visit_iushr() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ixor()
	 */
	@Override
	public void visit_ixor() {
		iop(X86Operation.XOR, true);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_jsr(int)
	 */
	@Override
	public void visit_jsr(int address) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_l2d()
	 */
	@Override
	public void visit_l2d() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_l2f()
	 */
	@Override
	public void visit_l2f() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_l2i()
	 */
	@Override
	public void visit_l2i() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ladd()
	 */
	@Override
	public void visit_ladd() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_laload()
	 */
	@Override
	public void visit_laload() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_land()
	 */
	@Override
	public void visit_land() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lastore()
	 */
	@Override
	public void visit_lastore() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lcmp()
	 */
	@Override
	public void visit_lcmp() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lconst(long)
	 */
	@Override
	public void visit_lconst(long value) {
		stack.push(new LongItem(new LongConstantLocation(value)));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ldc(java.lang.String)
	 */
	@Override
	public void visit_ldc(String value) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ldc(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_ldc(ConstClass value) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ldiv()
	 */
	@Override
	public void visit_ldiv() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lload(int)
	 */
	@Override
	public void visit_lload(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lmul()
	 */
	@Override
	public void visit_lmul() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lneg()
	 */
	@Override
	public void visit_lneg() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lookupswitch(int, int[], int[])
	 */
	@Override
	public void visit_lookupswitch(int defValue, int[] matchValues,
			int[] addresses) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lor()
	 */
	@Override
	public void visit_lor() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lrem()
	 */
	@Override
	public void visit_lrem() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lreturn()
	 */
	@Override
	public void visit_lreturn() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lshl()
	 */
	@Override
	public void visit_lshl() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lshr()
	 */
	@Override
	public void visit_lshr() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lstore(int)
	 */
	@Override
	public void visit_lstore(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lsub()
	 */
	@Override
	public void visit_lsub() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lushr()
	 */
	@Override
	public void visit_lushr() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lxor()
	 */
	@Override
	public void visit_lxor() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_monitorenter()
	 */
	@Override
	public void visit_monitorenter() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_monitorexit()
	 */
	@Override
	public void visit_monitorexit() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_multianewarray(icebird.metadata.constpool.ConstClass, int)
	 */
	@Override
	public void visit_multianewarray(ConstClass clazz, int dimensions) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_new(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_new(ConstClass clazz) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_newarray(int)
	 */
	@Override
	public void visit_newarray(int type) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_nop()
	 */
	@Override
	public void visit_nop() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_pop()
	 */
	@Override
	public void visit_pop() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_pop2()
	 */
	@Override
	public void visit_pop2() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_putfield(icebird.metadata.constpool.ConstField)
	 */
	@Override
	public void visit_putfield(ConstField fieldRef) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_putstatic(icebird.metadata.constpool.ConstField)
	 */
	@Override
	public void visit_putstatic(ConstField fieldRef) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ret(int)
	 */
	@Override
	public void visit_ret(int index) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_return()
	 */
	@Override
	public void visit_return() {
		while (!stack.isEmpty()) {
			Item v = stack.pop();
			
			if (v.getLocation().isStack()) {
				asm.lea(X86Register.ESP, X86Register.ESP, v.getCategory() * 4);
			}
			
			v.release();
		}
		
		stackFrame.emitReturn();
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_saload()
	 */
	@Override
	public void visit_saload() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_sastore()
	 */
	@Override
	public void visit_sastore() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_swap()
	 */
	@Override
	public void visit_swap() {
		Item a = stack.pop();
		Item b = stack.pop();
		
		if (a.getLocation().isFPUStack() || a.getLocation().isStack()) {
			a.load();
		} else if (b.getLocation().isFPUStack() || b.getLocation().isStack()) {
			b.load();
		}
		
		stack.push(a);
		stack.push(b);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_tableswitch(int, int, int, int[])
	 */
	@Override
	public void visit_tableswitch(int defValue, int lowValue, int highValue,
			int[] addresses) {
		// TODO Auto-generated method stub

	}
	
	private void callMethod(Method m) {
		Label callLabel = new Label(m.getMangledName());
		asm.call(callLabel);
		pushRetValue(m);
	}
	
	private void pushRetValue(Method m) {
		if (!m.returns()) return;
		
		BasicType t = m.getReturnType();
		
		// Double or Long
		if (t.isWide()) {
			GPR l = (GPR)pool.request(BasicType.Int);
			GPR h = (GPR)pool.request(BasicType.Int);
			
			stack.push(DoubleWordItem.getGPRWord(l, h, t));
		} else {
			GPR r = (GPR)pool.request(BasicType.Int);
			stack.push(WordItem.getGPRWord(r, t));
		}
	}
	
	private void dropParameters(Method m, boolean hasSelf) {
		BasicType[] argTypes = m.getArguments();
		int count = argTypes.length;
		
		for (int i = count - 1; i >= 0; i--) {
			BasicType arg = argTypes[i];
			Item tp = stack.pop();
			
			if (tp.getType() != arg) {
				// WARNING
			}
			
			tp.release();
		}
		
		if (hasSelf) {
			stack.pop().release();
		}
	}
	
	private void wreturn(BasicType t, boolean vret) {
		WordItem w = stack.popWord();
		
		if (!w.uses(X86Register.EAX)) {
			w.loadTo(X86Register.EAX);
		}
		
		w.release();
		
		if (vret) {
			visit_return();
		}
	}
	
	private final int getShiftForMultiplier(int val) {
		int mul = 2;
		for (int i = 1; i <= 31; i++) {
			if (val == mul) {
				return i;
			}
			mul <<= 1;
		}
		return -1;
	}
	
	private int getOffset(int i) {
		return -((i + 1) * 4);
	}
	
	private void wstore(BasicType t, int index) {
		int offset = getOffset(index);
		
		stack.loadLocal(offset);
		
		WordItem item = (WordItem)stack.pop();
		boolean vconst = item.getLocation().isConstant();
		
		if (vconst) {
			constLocals.put(index, item);
		} else {
			// not constant any more.
			constLocals.remove(index);
		}
		
		if (vconst) {
			if (item.getType() == BasicType.Float) {
				int v = Float.floatToRawIntBits(((FloatConstantLocation)item.getLocation()).getValue());
				asm.move_const(X86Register.EBP, offset, v);
			} else {
				// Store register
				// TODO: Make basic block optimization
				int v = ((IntegerConstantLocation)item.getLocation()).getValue();
				asm.move_const(X86Register.EBP, offset, v);
			}
		} else {
			Location loc = item.getLocation();
			
			if (loc.isFPUStack()) {
				FPUStack.fxch(stack.getFPUStack(), item);
				if (item.getType() == BasicType.Float) {
					asm.fstp(X86Register.EBP, offset);
				} else {
					asm.fistp(X86Register.EBP, offset);
				}
			} else if (loc.isStack()) {
				asm.pop(X86Register.EBP, offset);
			} else {
				item.load();
				asm.move(X86Register.EBP, offset, ((GPRLocation)loc).getGPR());
			}
		}
		
		item.release();
	}
	
	private void wload(BasicType t, int index) {
		Item cl = constLocals.get(index);
		
		if (cl != null) {
			stack.push(cl.clone());
		} else {
			stack.push(
				WordItem.getLocal(getOffset(index), t)
			);
		}
	}
	
	private boolean isConstant(Item v1) {
		return v1.getLocation().isConstant();
	}
	
	private boolean isConstant(Item v1, Item v2) {
		return v1.getLocation().isConstant() &&
		       v2.getLocation().isConstant();
	}
	
	// Prepare operands to operation.
	private boolean prepare(Item dst, Item src, boolean com) {
		if (com) {
			if (dst.getLocation().getWeight() < dst.getLocation().getWeight()) {
				src.load(); // Load source
				
				if (dst.getLocation().isStack() || dst.getLocation().isFPUStack()) {
					dst.load();
				}
				
				return true;
			}
		}
		
		if (src.getLocation().isStack() || src.getLocation().isFPUStack()) {
			src.load();
		}
		
		dst.load();
		
		return false;
	}

	private void iop(int op, boolean com) {
		IntegerItem v2 = stack.popInteger();
		IntegerItem v1 = stack.popInteger();
		
		if (isConstant(v1, v2)) {
			int vv1 = ((IntegerConstantLocation)v1.getLocation()).getValue();
			int vv2 = ((IntegerConstantLocation)v2.getLocation()).getValue();
			
			switch (op) {
			case X86Operation.ADD:
				visit_iconst(vv1 + vv2);
				break;
				
			case X86Operation.SUB:
				visit_iconst(vv1 - vv2);
				break;
				
			case X86Operation.AND:
				visit_iconst(vv1 & vv2);
				break;
				
			case X86Operation.OR:
				visit_iconst(vv1 | vv2);
				break;
				
			case X86Operation.XOR:
				visit_iconst(vv1 ^ vv2);
				break;
				
			default:
				throw new IllegalArgumentException();
			}
		} else {
			if (prepare(v1, v2, com)) {
				// (Un)Swap
				IntegerItem tmp = v2;
				v1 = v2;
				v2 = tmp;
			}
			
			GPR r1 = ((GPRLocation)v1.getLocation()).getGPR();
			if (v2.getLocation().isGPR()) {
				asm.arithOp(op, r1, ((GPRLocation)v2.getLocation()).getGPR());
			}
			
			if (v2.getLocation().isLocal()) {
				asm.arithOp(op, r1, X86Register.EBP, ((LocalLocation)v2.getLocation()).getOffset());
			}
			
			if (v2.getLocation().isConstant()) {
				asm.arithOp(op, r1, ((IntegerConstantLocation)v2.getLocation()).getValue());
			}
			
			v2.release();
			stack.push(v1);
		}
	}
}
